/*!
 * \file frservice_comm.c
 *
 * \brief 主机服务共通管理
 *
 * All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.\n
 * 关联连接共通管理
 *
 * \version 2.0
 * \author yaohl
 * \date 2015/11/27
 *
 */

#include "frcomm.h"
#include "frhash2.h"
#include "frlog.h"
#include "frmem.h"

#include "module.h"

#include "frservice_comm.h"

void frservice_add(void* p_frame_ref, int i_l7_proto, u_int ui_host_ip, u_short us_host_port
                 , void *p_data, unsigned int ui_data_size)
{
    ApmContext *p_context = (ApmContext *)p_frame_ref;
    Frservice_ref *p_st_serviceRef=NULL;
    Frlist_node* p_st_node=NULL;
    Host_service *p_st_service=NULL;
    char arr_key[20], *p_pos=NULL;
    int i_key_len=0;

    if(p_context == NULL
       || p_context->p_st_service_ref == NULL
       || p_context->p_st_service_ref->p_hash_hdr == NULL
       || p_context->p_st_service_ref->p_splock == NULL)
        return;

    i_key_len = sizeof(int) + sizeof(u_int) + sizeof(u_short);
    memset(arr_key, 0x00, i_key_len+1);
    p_pos = arr_key;
    *(int *)p_pos = i_l7_proto;
    *(u_int *)(p_pos + sizeof(int)) = ui_host_ip;
    *(u_short *)(p_pos + sizeof(int) + sizeof(u_int) ) = us_host_port;

    p_st_serviceRef = p_context->p_st_service_ref;
    pthread_spin_lock(p_st_serviceRef->p_splock);
    //查询l7相应的节点
    p_st_node = frhash2_getStr(p_st_serviceRef->p_hash_hdr, arr_key, i_key_len);
    if(p_st_node && p_st_node->data)
    {
        if(p_data == NULL || ui_data_size <= 0)
        {
            pthread_spin_unlock(p_st_serviceRef->p_splock);
            return;
        }

        p_st_service = (Host_service *)(p_st_node->data);
        if(p_st_service->p_data != NULL && p_st_service->ui_data_size == ui_data_size
           && memcmp(p_st_service->p_data, p_data, ui_data_size) ==0 )
        {
            pthread_spin_unlock(p_st_serviceRef->p_splock);
            return;
        }

        if(p_st_service->p_data)
            frfree(p_st_service->p_data);
        p_st_service->p_data = frmemdup(p_data, ui_data_size);
        if(p_st_service->p_data)
            p_st_service->ui_data_size = ui_data_size;

        pthread_spin_unlock(p_st_serviceRef->p_splock);
        return;
    }

    //生成新的节点
    p_st_service = (Host_service *)frmalloc(sizeof(Host_service));
    if(p_st_service == NULL)
    {
        pthread_spin_unlock(p_st_serviceRef->p_splock);
        return;
    }

    memset(p_st_service, 0x00, sizeof(Host_service));
    p_st_service->l7_proto = i_l7_proto;
    p_st_service->ip = ui_host_ip;
    p_st_service->port = us_host_port;
    if(p_data && ui_data_size > 0)
    {
        p_st_service->p_data = frmemdup(p_data, ui_data_size);
        p_st_service->ui_data_size = ui_data_size;
    }

    p_st_node = frlist_node_create(p_st_service);
    if(p_st_node == NULL)
    {
        if(p_st_service->p_data)
            frfree(p_st_service->p_data);
        frfree(p_st_service);
        pthread_spin_unlock(p_st_serviceRef->p_splock);
        return;
    }

    frhash2_addStr(p_st_serviceRef->p_hash_hdr, arr_key, i_key_len, p_st_node);
    pthread_spin_unlock(p_st_serviceRef->p_splock);

    return;
}

int frservice_get(void* p_frame_ref ,int i_l7_proto, u_int ui_host_ip, u_short us_host_port
                , void *p_data, unsigned int ui_data_size, int *p_is_ouput)
{
    ApmContext *p_context = (ApmContext *)p_frame_ref;
    Frservice_ref *p_st_serviceRef=NULL;
    Frlist_node* p_st_node=NULL;
    Host_service *p_st_service=NULL;
    char arr_key[20], *p_pos=NULL;
    int i_key_len=0;

    if(p_context == NULL
       || p_context->p_st_service_ref == NULL
       || p_context->p_st_service_ref->p_hash_hdr == NULL
       || p_context->p_st_service_ref->p_splock == NULL)
        return FR_FAIL;

    p_st_serviceRef = p_context->p_st_service_ref;

    i_key_len = sizeof(int) + sizeof(u_int) + sizeof(u_short);
    memset(arr_key, 0x00, i_key_len+1);
    p_pos = arr_key;
    *(int *)p_pos = i_l7_proto;
    *(u_int *)(p_pos + sizeof(int)) = ui_host_ip;
    *(u_short *)(p_pos + sizeof(int) + sizeof(u_int) ) = us_host_port;

    pthread_spin_lock(p_st_serviceRef->p_splock);
    p_st_node = frhash2_getStr(p_st_serviceRef->p_hash_hdr, arr_key, i_key_len);
    if(p_st_node == NULL || p_st_node->data == NULL)
    {
        pthread_spin_unlock(p_st_serviceRef->p_splock);
        return FR_FAIL;
    }

    p_st_service = (Host_service *)(p_st_node->data);
    if(p_st_service->l7_proto != i_l7_proto
       || p_st_service->ip != ui_host_ip
       || p_st_service->port != us_host_port)
    {
        pthread_spin_unlock(p_st_serviceRef->p_splock);
        return FR_FAIL;
    }

    //查询到该服务信息
    if(p_data == NULL || ui_data_size <= 0 || p_is_ouput == NULL)
    {
        pthread_spin_unlock(p_st_serviceRef->p_splock);
        return FR_SUCC;
    }

    //输出服务附加信息
    if(p_st_service->p_data == NULL || p_st_service->ui_data_size <= 0
       || p_st_service->ui_data_size < ui_data_size)
    {
        *p_is_ouput = FR_FAIL;
        pthread_spin_unlock(p_st_serviceRef->p_splock);
        return FR_SUCC;
    }

    memcpy(p_data, p_st_service->p_data, ui_data_size);
    *p_is_ouput = FR_SUCC;

    pthread_spin_unlock(p_st_serviceRef->p_splock);
    return FR_SUCC;
}
